01 - Wprowadzenie
Wprowadzenie do przetwarzania obrazów
Politechnika Poznańska, Instytut Robotyki i Inteligencji Maszynowej
Ćwiczenie laboratoryjne 1: Wstęp
Powrót do spisu treści ćwiczeń laboratoryjnych
Wstęp
Na zajęciach wykorzystywać będziemy język programowania Python oraz biblioteki dedykowane przetwarzaniu obrazów oraz – w mniejszym stopniu – uczeniu maszynowemu.
Python to język programowania wysokiego poziomu ogólnego przeznaczenia, o rozbudowanym pakiecie bibliotek standardowych, którego ideą przewodnią jest czytelność i klarowność kodu źródłowego. Jego składnia cechuje się przejrzystością i zwięzłością. Python wspiera różne paradygmaty programowania: obiektowy, imperatywny oraz w mniejszym stopniu funkcyjny. Posiada w pełni dynamiczny system typów i automatyczne zarządzanie pamięcią, będąc w tym podobnym do języków Perl, Ruby, Scheme czy Tcl. Podobnie jak inne języki dynamiczne jest często używany jako język skryptowy. Interpretery Pythona są dostępne na wiele systemów operacyjnych. Python rozwijany jest jako projekt Open Source zarządzany przez Python Software Foundation, która jest organizacją non-profit. Standardową implementacją języka jest CPython (napisany w C), ale istnieją też inne. (źródło: Wikipedia)
Kroki instalacji interpretera Pythona w systemie Windows
Rozwiń
Aby rozpocząć pracę z językiem Python należy pobrać jego interpreter.
Proszę pobrać dystrybucję Pythona w wersji 3.9.7 (najnowsza dostępna na dzień 2021.09.20):
https://www.python.org/ftp/python/3.9.7/python-3.9.7-amd64.exe
A następnie zainstalować. Na pierwszym ekranie należy zaznaczyć opcję: Add Python 3.9 to PATH
Pominięcie tej opcji uniemożliwi uruchomienie Pythona oraz jego narzędzi z konsoli, a także spowoduje, że IDE nie wykryje automatycznie lokalizacji interpretera.
Uwaga:
Po zainstalowaniu Pythona należy zrestartować komputer (w celu odświeżenia przez system zmiennej PATH).
Dodatkowe pakiety (biblioteki)
W celu instalacji dodatkowych bibliotek wykorzystane zostanie narzędzie pip obsługiwane przez wykorzystywane środowisko programistyczne. Biblioteki do zainstalowania: opencv-contrib-python
, scikit-image
, matplotlib
Szczegóły przeprowadzenia tego procesu zostały omówione przy opisie tworzenia pierwszego projektu.
Kroki instalacji IDE PyCharm
Rozwiń
Na zajęciach wykorzystywane jest środowisko programistyczne PyCharm, które dostępne jest pod adresem:
https://www.jetbrains.com/pycharm/
Przy pierwszym uruchomieniu zostaną Państwo poproszeni o wybór schematu klawiszy (w przypadku przyzwyczajenia do skrótów klawiszowych z Visual Studio warto wybrać tę opcję) oraz schematu kolorów (np. Darcula).
Uwaga:
Po instalacji wszystkich elementów przy pisaniu programu w PyCharm powinny pokazywać się podpowiedzi dotyczące dostępnych funkcji. W celu ich wywołania należy wcisnąć Ctrl+Spacja po napisaniu kilku pierwszych liter. Aby podejrzeć argumenty wywoływanej funkcji, należy, mając kursor pomiędzy nawiasami nacisnąć Ctrl+Shift+Spacja. Możliwe jest również najechanie na funkcje wskaźnikiem myszki z wciśniętym klawiszem Ctrl.
Wykorzystywane biblioteki
OpenCV (
opencv-contrib-python
)Największa i najbardziej znana biblioteka służąca do przetwarzania obrazów. Początkowo napisana w języku C, obecnie w C++, ale posiadająca zbiór wrapperów umożliwiających wywoływanie funkcji m.in. w języku Python czy Java.
Jak czytać dokumentację w OpenCV - tipy
Bazując na przykładzie funkcji
cv2.cvtColor
, którego dokumentacja znajduje się pod tym linkiem, można zauważyć, że:na początku pokazano dokumentację dla języka C++, a dopiero następnie dla języka Pythona. W przypadku Pythona, w pierwszej linijce znajduje się informacja, że funkcja ta jest dostępna w module
cv2
lubcv.
.następnie zapoznać się można z opisem funkcji, a czasem zasadą działania algorytmu, przykładowym użyciem oraz występującymi typami danych.
na końcu można znaleźć opis i typy parametrów wejściowych oraz wartości zwracane przez funkcję.
Numpy (
numpy
)Biblioteka do przetwarzania tablic i macierzy. W szczególności wykorzystywana do operacji matematycznych.
Scikit-image (
scikit-image
)Biblioteka do przetwarzania obrazów, napisana w składni i paradygmacie języka Python. Brak obsługi video.
Tworzenie pierwszego projektu w IDE
Rozwiń
Należy uruchomić PyCharm a następnie utworzyć nowy projekt. Okno podczas pierwszego uruchomienia przedstawiono poniżej. Przy kolejnych uruchomieniach ładowany będzie poprzedni projekt i w celu utworzenia nowego należy wybrać File->New Project.
Proszę zwrócić uwagę na nazwę oraz lokalizację projektu.
UWAGA
W nazwie oraz lokalizacji projektu zalecamy nie stosować polskich znaków diakrytycznych oraz spacji (używać podkreślników). Podczas tworzenia nowego projektu domyślnie wybrana jest opcja utworzenia nowego środowiska wirtualnego (virtualenv), które izoluje Państwa projekt i jest preferowanym podejściem (np. jedno środowisko wirtualne dla wszystkich projektów z przedmiotu). Różne wirtualne środowiska mogą zawierać różne biblioteki i/lub wersje tych samych bibliotek.
Na zajęciach w laboratorium, ze względów technicznych proszę jednak wybrać opcję Existing interpreter
Pierwsze uruchomienie skutkuje błędem C:\Users\lab\AppData\Local\Programs\Python\Python39\python.exe
) jak na rysunku poniżej. Potwierdzić przyciskiem ok.
Ostatecznie okno tworzenia nowego projektu powinno wyglądać jak poniżej:
Przy pierwszym uruchomieniu (w laboratorium nie jest to konieczne, gdyż wszystko już jest zainstalowane) należy zainstalować dodatkowe biblioteki. W tym celu z menu File wybrać Settings, a następnie Project:
Należy następnie w okno wyszukiwania wpisywać i zainstalować następujące pakiety (poczekać do końca instalacji przed dodaniem kolejnej): matplotlib, opencv-contrib-python, scikit-image
Możemy teraz dodać nowy plik *.py i wkleić przykładowy program zamieszczony poniżej, uruchomić go i obserwować efekty działania.
Pierwszy program
Wklej do pliku main.py
następujący kod. Uruchom i zaobserwuj efekty jego działania:
import cv2
def main():
= cv2.VideoCapture(0) # open the default camera
cap
= ord('a')
key while key != ord('q'):
# Capture frame-by-frame
= cap.read()
ret, frame
# Our operations on the frame comes here
# Convert RGB image to grayscale
= cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
img_gray # Blur the image
= cv2.GaussianBlur(img_gray, (7, 7), 1.5)
img_filtered # Detect edges on the blurred image
= cv2.Canny(img_filtered, 0, 30, 3)
img_edges
# Display the result of our processing
'result', img_edges)
cv2.imshow(# Wait a little (30 ms) for a key press - this is required to refresh the image in our window
= cv2.waitKey(30)
key
# When everything done, release the capture
cap.release()# and destroy created windows, so that they are not left for the rest of the program
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
Uwaga!
Zwróć uwagę na cyfrę0
w liniicap = cv2.VideoCapture(0)
. Oznacza ona numer kamerki, która zostanie użyta do przechwytywania obrazu. W przypadku, gdybyśmy chcieli użyć innej kamerki, należy podać jej numer. W przypadku, gdybyśmy chcieli użyć pliku wideo, należy podać ścieżkę do pliku wideo.
Wczytywanie, zapisywanie i wyświetlanie obrazów
Znajdź w dokumentacji funkcje cv2.imread
, cv2.imwrite
oraz cv2.imshow
.
Uwaga:
Funkcjacv2.imread
jako drugi parametr przyjmuje flagę informującą o sposobie wczytywania obrazu. Flagacv2.IMREAD_COLOR
w przypadku wczytywania obrazu kolorowego orazcv2.IMREAD_GRAYSCALE
w przypadku obrazu w skali szarości. Szczegóły w dokumentacji: ImreadModes.
💥 Zadanie do wykonania 💥
Wyszukaj i pobierz z internetu dowolny obraz. Następnie, wczytaj go, wyświetl na ekranie i zapisz pod inną nazwą korzystając z powyższych funkcji. Znajdź nowo zapisany plik na dysku.
Uwaga:
Umieść obraz w tym samym katalogu co plikmain.py
lub podaj pełną ścieżkę do pliku.
Obrazy a piksele - przechowywanie obrazu w pamięci
Obraz wczytany z pliku lub pobrany z kamery przejwia pewne istotne cechy:
jest przechowywany jako macierz (tablica) typu
numpy.array
jego rozmiar to:
wysokość_obrazu x szerokość_obrazu x liczba_kanałów
, gdzie:- szerokość i wysokość to rozdzielczość wyrażona w pikselach
- liczba kanałów określa ile składowych ma dany piksel (3 w przypadku obrazu kolorowego i 1 w przypadku obrazu w skali szarości).
wartość każdego piksela mieści się w zakresie 0 – 255.
Poniżej zamieszczono wycinek obrazu wraz z wartościami jasności poszczególnych kanałów dla wszystkich pikseli w otoczeniu. Obraz kolorowy (BGR) - każdy piksel ma trzy kanały, czyli przechowuje trzy wartości:
Obraz w skali szarości (grayscale) - każdy piksel ma jeden kanał, czyli przechowuje jedną wartość:
Kształt macierzy przechowującej obraz po wczytaniu można sprawdzić za pomocą komend (obie działają identycznie):
print(np.shape(<nazwa_macierzy>))
print(<nazwa_macierzy>.shape)
💥 Zadanie do wykonania 💥
Przetestuj działanie powyższych funkcji na wczytanym obrazie (lub kilku obrazach).
💥 Zadanie do wykonania 💥
Zapoznaj się z informacjami dostępnymi pod linkiem, które dotyczą podstawowych operacji na macierzach obrazowych. Następnie korzystając z obraz … Korzystając z obrazu z poprzedniego zadania, odczytaj wartość jasności piksela w położeniu 220, 270 kiedy obraz jest wczytany jako kolorowy oraz kiedy obraz jest wczytany w skali szarości. Zwróć uwagę na liczbę otrzymywanych wartości.
Uwaga:
W celu połączenia zmiennych z istniejącym tekstem można wykorzystać tak zwane f-string:print(f'Pixel value at [220, 270]: {px}')
Zwróć uwagę na literę
f
przed cudzysłowem otwierającym ciąg tekstowy - powoduje ona, że kod wpisany wewnątrz ciągu tekstowego pomiędzy klamrami{}
będzie wykonany jako kod Pythonowy i w jego miejsce zostanie wstawiona zwrócona wartość. Dla dociekliwych: dobre podsumowanie starszych i obecnych możliwości formatowania tekstu w języku Python znajduje się tutaj.
💥 Zadanie do wykonania 💥
Wycinając dowolny prostokąt (często nazywany obszarem zainteresowania - ROI), zduplikuj fragment obrazu, wyświetl go w osobnym oknie, a następnie wklej w inne miejsce oryginalnego obrazu.
💥 Zadanie do wykonania 💥
Wykorzystaj funkcję cv2.cvtColor
i zmień format kolorów z domyślnego dla OpenCV BGR
na szeroko używany RGB
. Wyświetl oba obrazy za pomocą cv2.imshow
). Zwróć uwagę, jak ta zmiana wypłynęła na obrazy.
Uwaga:
Skąd rozbieżność między światem RGB a formatem BGR w OpenCV? Odpowiedź możesz znaleźć w tym pytaniu.
💥 Zadanie do wykonania 💥
Pobierz obraz wyświetlony poniżej (prawy przycisk myszy -> “Zapisz grafikę jako…”). Korzystając z funkcji cv2.split
podzielić obraz na trzy składowe i w trzech niezależnych oknach wyświetlić osobno składową czerwoną, niebieską oraz zieloną.
Funkcja cv2.split
jest kosztowna obliczeniowo. Wykorzystaj wielowymiarowe indeksowanie numpy (slicing - preferowany sposób w Pythonie) do uzyskania tego samego efektu.
Obsługa kamer oraz wideo
Biblioteka OpenCV zapewnia identyczny interfejs dostępu do poszczególnych klatek obrazu dla kamer oraz plików wideo. W obu przypadkach wykorzystywana jest ta sama klasa cv2.VideoCapture
, którą inicjalizujemy inną wartością, tj. numerem kamery lub nazwą pliku wideo. Dalsza obsługa jest w obu przypadkach identyczna. Zapoznaj się z przykładem.
💥 Zadanie do wykonania 💥
Jeśli komputer jest wyposażony w kamerę to otwórz ją i wczytuj kolejne klatki po naciśnięciu klawisza spacja.
💥 Zadanie do wykonania 💥
Pobierz plik wideo i wczytaj z niego kolejne klatki jak w przypadku kamery. Dodaj obsługę zdarzenia polegającego na wykryciu końca pliku. W tym celu wykorzystaj wartość true/false zwracaną przez metodę read
klasy VideoCapture.
Zadania do samodzielnej realizacji
💥 Zadanie do wykonania 💥
Dla przypomnienia podstaw języka Python wykonaj zadania z interaktywnego notatnika: https://colab.research.google.com/drive/1h9ZuXPR-WKHT5giNJdlF6TAhPjRgSS0k?usp=sharing
💥 Zadanie do wykonania 💥
OpenCV nie jest jedyną biblioteką do przetwarzania obrazów w Pythonie. Inną, również popularną biblioteką jest scikit-image
. Została ona napisana w języku Python jako dedykowana biblioteka do przetwarzania obrazów. Charakteryzuje ją bardzo bogata dokumentacja i zbiór przykładów.
Zapoznaj się z pierwszymi krokami oraz zbiorem przykładów.
💥 Zadanie do wykonania 💥
Zrealizować prosty pokaz zdjęć z wybranego folderu: wybór następnego/poprzedniego zdjęcia ma się odbywać za pomocą dwóch różnych klawiszy (np. q, w). Pokaz ma być cykliczny, np. po osiągnięciu ostatniego zdjęcia i wciśnięciu klawisza ‘następny’ wczytywać się ma pierwsze zdjęcie.